using UnityEngine;
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;

public abstract class ConsoleComponent
{
    public String Name
    {
        get { return GetType().ToString(); }
    }

    public abstract void OnDrawing();

    public virtual void OnUpdate()
    {
    }
}

public class DebugConsole : MonoBehaviour
{
    public static float BTN_R_WIDTH = 0.15f;
    public static float BTN_R_HEIGHT = 0.1f;
    public static float R_SPACING = 0.01f;

    #region Singleton

    private static DebugConsole instance;

    public static DebugConsole GetInstance()
    {
        if (instance == null)
        {
            throw new Exception("Please initialize it before use, and make sure 'DEBUG_CONSOLE was defined");
        }

        return instance;
    }

    #endregion

    #region Setup

    private List<ConsoleComponent> componentsList;

    public static void Init()
    {
#if DEBUG_CONSOLE

        Watchdog.Init();

        // Create instance
        GameObject go = new GameObject("[DebugConsole]");
        instance = go.AddComponent<DebugConsole>();

        instance._Init();
#endif
    }

    private void _Init()
    {
        // Add build-in components
        componentsList = new List<ConsoleComponent>();
        AddConsoleComponent(new FpsDetector()); 
        AddConsoleComponent(new MainMenuTrigger());
        AddComponentToMainMenu(new WatchdogViewer());
        AddComponentToMainMenu(new CommandButtonPanel());
        AddComponentToMainMenu(new TimerScaler());

        AddConsoleCommand(new FieldReflectCommand());

        AddConsoleCommand("filter", (p) =>
        {
        Watchdog.Log("DebugConsole", Watchdog.FiltersInfo());

        }, false);

        // Log success info
        Watchdog.Log("DebugConsole", "**Initialized**");
    }

    public void AddConsoleComponent(ConsoleComponent component)
    {
        componentsList.Add(component);
    }

    public void AddComponentToMainMenu(ConsoleComponent component)
    {
        GetMainMenu().AddConsoleComponent(component);
    }

    public void AddConsoleCommand(string id, Action<List<string>> callback, bool isPreset = false)
    {
        if (id.IndexOf(" ") != -1)
        {
            Debug.LogError(string.Format("The command id '{0}' you defined in console should not contains space", id));
            return;
        }

        GetCommondInput().AddConsoleCommand(id, callback);

        if (isPreset)
            AddPresetCommandStr(id);
    }

    public void AddConsoleCommand(ConsoleConmand command, bool isPreset = false)
    {
        if (command.id.IndexOf(" ") != -1)
        {
            Debug.LogError(string.Format("The command id '{0}' you defined in console should not contains space",
                command.id));
            return;
        }

        GetCommondInput().AddConsoleCommand(command);

        if (isPreset)
            AddPresetCommandStr(command.id);
    }

    public void AddPresetCommandStr(string commandId)
    {
        GetMainMenu()
            .GetConsoleComponent<CommandButtonPanel>()
            .AddPresetCommandStr(commandId);
    }

    public void SetFinderToRelectCommand(IGameGlobalObjectFinder finder)
    {
#if DEBUG_CONSOLE
        GetCommondInput().GetCommand<FieldReflectCommand>(FieldReflectCommand.ID).SetFinder(finder);
#endif
    }

    public T GetConsoleComponent<T>() where T : ConsoleComponent
    {
        foreach (ConsoleComponent c in componentsList)
            if (c is T) return c as T;

        return null;
    }

    internal CommandInput GetCommondInput()
    {
        return GetMainMenu().GetConsoleComponent<WatchdogViewer>().commandInput;
    }

    private ConsoleMainMenu GetMainMenu()
    {
        return GetConsoleComponent<MainMenuTrigger>().mainMenu;
    }

    #endregion

#if DEBUG_CONSOLE && !UNITY_EDITOR
     
    void OnApplicationPause(bool paused)
    {
        if (!paused)
        {
            globalToggle = !globalToggle;
        }
    }

#endif

#if DEBUG_CONSOLE

    private bool globalToggle = true;

    void OnGUI()
    {
        for (int i = 0; i < componentsList.Count; i++)
            componentsList[i].OnDrawing();
    }

    void Update()
    {
        for (int i = 0; i < componentsList.Count; i++)
            componentsList[i].OnUpdate();
    }

#endif
}
